package com.jzo2o.health.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.health.mapper.ReservationSettingMapper;
import com.jzo2o.health.model.domain.ReservationSetting;
import com.jzo2o.health.model.dto.request.ReservationSettingUpsertReqDTO;
import com.jzo2o.health.model.dto.response.ReservationDateResDTO;
import com.jzo2o.health.model.dto.response.ReservationSettingResDTO;
import com.jzo2o.health.service.IReservationSetting;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author itlxc
 * @since 2024-10-21
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ReservationSettingImpl extends ServiceImpl<ReservationSettingMapper, ReservationSetting> implements IReservationSetting {

    private final ReservationSettingMapper reservationSettingMapper;


    /**
     * 根据月份查询预约设置
     * @param date
     * @return
     */
    @Override
    public List<ReservationSettingResDTO> getReservationSettingByMonth(String date) {
        YearMonth yearMonth = YearMonth.parse(date, DateTimeFormatter.ofPattern("yyyy-MM"));
        LocalDate beginDate = yearMonth.atDay(1);
        LocalDate endDate = yearMonth.atEndOfMonth();
        return reservationSettingMapper.getReservationSettingByMonth(beginDate, endDate);
    }

    /**
     * 编辑预约设置
     * @param reservationSettingUpsertReqDTO
     */
    @Override
    public void editNumberByDate(ReservationSettingUpsertReqDTO reservationSettingUpsertReqDTO) {
        // 参数校验
        if (reservationSettingUpsertReqDTO.getNumber() <= 0 || reservationSettingUpsertReqDTO.getNumber() > 999) {
            throw new ForbiddenOperationException("预约人数需要大于0，小于1000");
        }
        ReservationSetting reservationSetting = this.lambdaQuery()
                .eq(ReservationSetting::getOrderDate, reservationSettingUpsertReqDTO.getOrderDate())
                .one();
        if (ObjectUtil.isNull(reservationSetting)) {
            reservationSetting = new ReservationSetting();
            BeanUtil.copyProperties(reservationSettingUpsertReqDTO, reservationSetting);
            this.save(reservationSetting);
            return;
        }
        if (reservationSettingUpsertReqDTO.getNumber() < reservationSetting.getReservations()) {
            throw new ForbiddenOperationException("预约人数不能小于已预约人数");
        }
        BeanUtil.copyProperties(reservationSettingUpsertReqDTO, reservationSetting);
        this.updateById(reservationSetting);
    }

    /**
     * 批量新增预约设置
     * @param file
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addBatch(MultipartFile file) {
        // 验证文件类型和大小
        try {
            // 验证文件类型和大小
            if (file == null || file.isEmpty()) {
                log.warn("文件为空");
                throw new IllegalArgumentException("文件不能为空");
            }
            if (file.getSize() > 10 * 1024 * 1024) { // 限制文件大小为10MB
                log.warn("文件大小超过限制: {}MB", file.getSize() / (1024 * 1024));
                throw new IllegalArgumentException("文件大小超过限制");
            }
            String contentType = file.getContentType();
            if (!"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType)) {
                log.warn("不支持的文件类型: {}", contentType);
                throw new IllegalArgumentException("不支持的文件类型");
            }
            List<ReservationSetting> list = new ArrayList<>();
            EasyExcel.read(file.getInputStream(), ReservationSettingUpsertReqDTO.class,
                    new PageReadListener<ReservationSettingUpsertReqDTO>(dtoList -> {
                for (ReservationSettingUpsertReqDTO dto : dtoList) {
                    log.info("读取到一条数据{}", JSONUtil.toJsonStr(dto));
                    if (dto.getNumber() <= 0 || dto.getNumber() > 999) {
                        throw new ForbiddenOperationException("预约人数需要大于0，小于1000");
                    }
                    // 如果已存在预约设置数据则更新，否则进行新增。
                    ReservationSetting reservationSetting = this.lambdaQuery()
                            .eq(ReservationSetting::getOrderDate, dto.getOrderDate())
                            .one();
                    if (ObjectUtil.isNull(reservationSetting)) {
                        reservationSetting = new ReservationSetting();
                        BeanUtil.copyProperties(dto, reservationSetting);
                        list.add(reservationSetting);
                        continue;
                    }
                    if (dto.getNumber() < reservationSetting.getReservations()) {
                        throw new ForbiddenOperationException("预约人数不能小于已预约人数");
                    }
                    BeanUtil.copyProperties(dto, reservationSetting);
                    list.add(reservationSetting);
                }
            })).sheet().doRead();
            if (list.isEmpty()) {
                log.warn("没有需要处理的数据");
                throw new IllegalArgumentException("没有需要处理的数据");
            }
            this.saveBatch(list.stream().filter(item -> ObjectUtil.isNull(item.getId())).collect(Collectors.toSet()));
            this.updateBatchById(list.stream().filter(item -> ObjectUtil.isNotNull(item.getId())).collect(Collectors.toSet()));
            log.info("批量新增预约设置成功");
        } catch (ForbiddenOperationException e) {
            log.error("操作被禁止: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("处理文件时发生错误: {}", e.getMessage(), e);
            throw new RuntimeException("处理文件时发生错误", e);
        }
    }

    /**
     * 按月查询可预约日期
     * @param month
     * @return
     */
    @Override
    public ReservationDateResDTO getReservationByMonth(String month) {
        YearMonth yearMonth = YearMonth.parse(month, DateTimeFormatter.ofPattern("yyyy-MM"));
        LocalDate beginDate = yearMonth.atDay(1);
        LocalDate endDate = yearMonth.atEndOfMonth();
        List<String> dateList = reservationSettingMapper.getReservationByMonth(beginDate, endDate);
        return new ReservationDateResDTO(dateList);
    }
}
